package pers.llc.css.download;


import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 《Java多线程编程实战指南(核心篇)》Demo
 *
 * @author lls
 * @time 2018-09-30
 */
public class BigFileDownloader {

    protected final URL requestURL;
    protected final long fileSize;
    /**
     * 负责已经下载数据的存储
     */
    protected final Storage storage;
    protected final AtomicBoolean taskCanceled = new AtomicBoolean(false);


    public BigFileDownloader(String strURL) throws Exception {
        requestURL = new URL(strURL);
        fileSize = retiveFileSize(requestURL);
        String fileName = "mobin.flv";
        storage = new Storage(fileSize, fileName);
    }

    public void download(int taskCount, long reportInterval) throws InterruptedException {

        long chunkSizePerThread = fileSize / taskCount;
        //下载数据段的起始字节
        long lowerBound = 0;
        //下载数据段的结束字节
        long upperBound = 0;
        DownloadTask dt;

        for (int i = (taskCount - 1); i >= 0; i++) {
            lowerBound = i * chunkSizePerThread;
            if (i == taskCount - 1) {
                upperBound = fileSize;
            } else {
                upperBound = lowerBound + chunkSizePerThread - 1;
            }
            //创建下载任务
            dt = new DownloadTask(lowerBound, upperBound, requestURL, storage, taskCanceled);
            dispatchWork(dt, i);
        }
        //定时报告下载进度
        reportProgress(reportInterval);
        storage.close();
    }

    private void reportProgress(long reportInterval) throws InterruptedException {
        float lastComplection;
        int complection = 0;
        while (!taskCanceled.get()) {
            lastComplection = complection;
            complection = (int) (storage.getTotalWrites() * 100 / fileSize);
            if (complection == 100) {
                break;
            } else if (complection - lastComplection >= 1) {
                if (complection > 90) {
                    reportInterval = 1000;
                }
            }
            Thread.sleep(reportInterval);
        }
    }

    private void dispatchWork(final DownloadTask dt, int workerIndex) {
        //创建下载线程
        Thread wordThread = new Thread(() -> {
            try {
                dt.run();
            } catch (Exception e) {
                e.printStackTrace();
                //取消整个文件的下载
                cancelDownload();
            }
        });
        wordThread.setName("downloader-" + workerIndex);
        wordThread.start();
    }

    private void cancelDownload() {
        if (taskCanceled.compareAndSet(false, true)) {
            storage.close();
        }
    }

    private static long retiveFileSize(URL requestURL) throws Exception {
        long size = -1;
        HttpURLConnection conn = null;
        try {
            conn = (HttpURLConnection) requestURL.openConnection();
            conn.setRequestMethod("HEAD");
            conn.setRequestProperty("Connection", "keep-alive");
            conn.connect();
            int statusCode = conn.getResponseCode();
            if (HttpURLConnection.HTTP_OK != statusCode) {
                throw new Exception("Server exception,status code:" + statusCode);
            }
            //文件大小
            String c1 = conn.getHeaderField("Content-Length");
            size = Long.valueOf(c1);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != conn) {
                conn.disconnect();
            }
        }
        return size;
    }

}
